﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using XNAGuiLib.GuiLibAction;
using XNAGuiLib.GuiLibKeyboard;
using XNAGuiLib.GuiLibResourceManager;
using XNAGuiLib.GuiLibScrollbar;

namespace XNAGuiLib.GuiLibTextfield
{
    public class TextfieldObject : InterfaceObject
    {

        #region Field - RelativePosition
        /// <summary>
        /// gets or sets InterfaceObjects relative position (when added in a different InterfaceObject)
        /// </summary>
        new public Vector2 RelativePosition
        {
            get
            {
                return _relativePosition;
            }
            set
            {
                _relativePosition = value;

                Background.Position = _position + value;
                BorderLeft.Position = _position + value;
                BorderRight.Position = _position + value;
                BorderTop.Position = _position + value;
                BorderBottom.Position = _position + value;
                Cursor.Position = _position + value;
            }
        }
        #endregion

        #region Field - AllowOutOfBoundsContent
        protected bool _allowOutOfBoundsContent = false;
        /// <summary>
        /// gets or sets if this component allows the content to be out of bounds
        /// </summary>
        public bool AllowOutOfBoundsContent
        {
            get
            {
                return _allowOutOfBoundsContent;
            }
            set
            {
                _allowOutOfBoundsContent = value;
            }
        }
        #endregion

        #region Field - Bounds
        /// <summary>
        /// gets or sets the bounds (width and height) of this InterfaceObject
        /// </summary>
        public new Vector2 Bounds
        {
            get
            {
                return _bounds;
            }
            set
            {
                _bounds = value;
                InitializeComponentsBounds();
            }
        }
        #endregion

        #region Field - Content
        protected string _content = "";
        /// <summary>
        /// gets or sets the complete content (even unshown/invisible)
        /// </summary>
        public string Content
        {
            get
            {
                return _content;
            }
            set
            {
                _content = value;
            }
        }
        #endregion

        #region Field - Textmark
        protected int _textmark;
        /// <summary>
        /// gets or sets the textmark index in the string
        /// </summary>
        public int Textmark
        {
            get
            {
                return _textmark;
            }
            set
            {
                _textmark = value;
            }
        }
        #endregion

        #region Field - StyleType
        protected GuiResourceManager.ResourceManagerType _styleType;
        /// <summary>
        /// gets or sets the textmark index in the string
        /// </summary>
        public GuiResourceManager.ResourceManagerType StyleType
        {
            get
            {
                return _styleType;
            }
            set
            {
                _styleType = value;
            }
        }
        #endregion

        #region Field - TextTarget
        protected TextObject _textTarget;
        /// <summary>
        /// gets or sets the TextTarget (TextObject) to which the Content will be send
        /// </summary>
        public TextObject TextTarget
        {
            get
            {
                return _textTarget;
            }
            set
            {
                _textTarget = value;
            }
        }

        #endregion

        #region Field - ScrollbarVisible
        protected bool _scrollbarVisible = true;
        /// <summary>
        /// gets or sets if the TextfieldObject scrollbar is visible
        /// </summary>
        public bool ScrollbarVisible
        {
            get
            {
                return _scrollbarVisible;
            }
            set
            {
                _scrollbarVisible = value;
            }
        }
        #endregion

        #region Field - KeyProcessor
        protected KeyProcessor _keyProcessor;
        /// <summary>
        /// gets the current keyProcessor used by this TextfieldObject
        /// </summary>
        public KeyProcessor KeyProcessor
        {
            get
            {
                return _keyProcessor;
            }
        }
        #endregion



        #region Protected Field - _oldTextmark
        protected int _oldTextmark;
        #endregion

        #region Protected Field - _lines
        protected int _lines;
        #endregion

        #region Protected Field - _linesUp
        protected int _linesUp;
        #endregion

        #region Protected Field - _rcm
        // initializing the resourceContentManager for default style 
        // (this will be changed in 'styled' TextfieldObject classes)
        protected ResourceContentManager _rcm = null;
        #endregion

        #region Protected Field - TextObject
        protected TextObject Text;
        #endregion

        #region Protected Field - Scrollbar
        protected ScrollbarObject _scrollbar;
        /// <summary>
        /// gets or sets the Scrollbar for this TextfieldObject
        /// </summary>
        public ScrollbarObject Scrollbar
        {
            get
            {
                return _scrollbar;
            }
            set
            {
                _scrollbar = value;
                Scrollbar.ScrollTarget = this._keyProcessor;
                // set the scrollbars initial scroll steps
                Scrollbar.ScrollSteps = 0;
            }
        }
        #endregion

        #region Protected Fields - TextureObjects
        protected TextureObject Background;
        protected TextureObject BorderLeft;
        protected TextureObject BorderRight;
        protected TextureObject BorderTop;
        protected TextureObject BorderBottom;
        protected TextureObject Cursor;
        #endregion


        #region Constructor - TextfieldObject(Game game, string name, string content, Vector2 relPosition, Vector2 bounds, bool scrollbarVisible)
        public TextfieldObject(Game game, string name, string content, Vector2 relPosition, Vector2 bounds, Color textColor, GuiResourceManager.ResourceManagerType styleType, bool scrollbarVisible)
            : base(game, name, relPosition, true)
        {
            // set (up) the ResourceContentManager 
            _rcm = GuiResourceManager.Instance(this.Game, styleType);
            // set up default fields (Graphic & Text Components excluded)
            #region Init - Base Fields
            // set the Content to the inner field
            _content = content;
            // set the cursor to the end of content
            _textmark = _content.Length;
            _oldTextmark = _content.Length;
            // set the SpriteFont for this TextfieldObject
            _font = GuiResourceManager.Instance(this.Game).FontManager.Load<SpriteFont>("Verdana8");
            // set the bounds of this TextfieldObject
            _bounds = bounds;
            // set the styletype of this TextfieldObject
            _styleType = styleType;
            // set the scrollablitiy of this TextfieldObject
            _scrollbarVisible = scrollbarVisible;
            #endregion
            // set the KeyProcessor for this TextfieldObject
            #region Init - KeyProcessor
            _keyProcessor = new KeyProcessor();
            _keyProcessor.LineWidth = (int)this.Bounds.X - 4;
            _keyProcessor.Font = _font;
            #endregion
            // set (up) the scrollbar ScrollbarObject
            #region Init - Scrollbar
            switch (styleType)
            {
                case GuiResourceManager.ResourceManagerType.StyleDefault:
                    _scrollbar = new DefaultScrollbar(this.Game, this.Name + "_scrollbar", new Vector2((_bounds.X - 16.0f ) / 2, 0.0f), new Vector2(17.0f, this.Height));
                    break;

                case GuiResourceManager.ResourceManagerType.StyleHorizons:
                    _scrollbar = new HorizonsScrollbar(this.Game, this.Name + "_scrollbar", new Vector2((_bounds.X - 16.0f) / 2, 0.0f), new Vector2(17.0f, this.Height));
                    break;

                case GuiResourceManager.ResourceManagerType.StyleMac:
                    float crnHeight = _rcm.Load<Texture2D>("tf_crn_tr").Height;
                    _scrollbar = new MacScrollbar(this.Game, this.Name + "_scrollbar", new Vector2((_bounds.X - 15.0f) / 2, crnHeight / 2), new Vector2(15.0f, this.Height - (crnHeight * 2)));
                    break;

            }
            // set the scrollbars target (manipulating the actual view via the IScroll interface methods
            _scrollbar.ScrollTarget = this._keyProcessor;
            // set the scrollbars initial scroll steps
            _scrollbar.ScrollSteps = 0;
            #endregion
            // set (up) the background TextureObject
            #region Init - Background
            Background = new TextureObject(_rcm.Load<Texture2D>("tf_bg"), "", Statics.ZeroVector2, Statics.ZeroVector2);
            Background.Name = this.Name + "_background";
            #endregion
            // set (up) the vertical border (left) TextureObjects
            #region Init - BorderLeft
            BorderLeft = new TextureObject(_rcm.Load<Texture2D>("tf_brd_lr"), "", Statics.ZeroVector2, Statics.ZeroVector2);
            BorderLeft.Name = this.Name + "_borderleft";
            #endregion
            // set (up) the vertical border (right) TextureObjects
            #region Init - BorderRight
            BorderRight = new TextureObject(_rcm.Load<Texture2D>("tf_brd_lr"), "", Statics.ZeroVector2, Statics.ZeroVector2);
            BorderRight.Rotation = MathHelper.ToRadians(180.0f);
            BorderRight.Name = this.Name + "_borderright";
            #endregion
            // set (up) the horizontal border (top) TextureObjects
            #region Init - BorderTop
            BorderTop = new TextureObject(_rcm.Load<Texture2D>("tf_brd_tb"), "", Statics.ZeroVector2, Statics.ZeroVector2);
            BorderTop.Name = this.Name + "_bordertop";
            #endregion
            // set (up) the horizontal border (bottom) TextureObjects
            #region Init - BorderBottom
            BorderBottom = new TextureObject(_rcm.Load<Texture2D>("tf_brd_tb"), "", Statics.ZeroVector2, Statics.ZeroVector2);
            BorderBottom.Rotation = MathHelper.ToRadians(180.0f);
            BorderBottom.Name = this.Name + "_borderbottom";
            #endregion
            // check multLine & set (up) cursor Position & content TextObject
            #region Init - Text Position
            // initializing the Text (Textobject) for presentation of content
            Text = new TextObject(_content, _font, "text", new Vector2(3, 2), Statics.ZeroVector2);
            // calculate total number of lines with the height given in the constructor and the height of a default MeasureString-method
            _lines = (int)((Height + 2) / (_font.MeasureString("A").Y - 2));
            // Console.WriteLine(Height + " / " + (_font.MeasureString("A").Y - 2) + " = " + _lines);
            // calculate number of lines above the current line
            _linesUp = (_lines - 1);
            // set the KeyProcessor's TotalLines-property to the textfield's total number of lines
            _keyProcessor.TotalLines = _lines;
            // set the textcolor
            this.Text.TextColor = textColor;
            #endregion
            // set (up) the cursor TextureObject
            #region Init - Cursor
            Cursor = new TextureObject(_rcm.Load<Texture2D>("tf_cursor"), this.Name + "_cursor", Statics.ZeroVector2, Statics.ZeroVector2);
            #endregion

            InitializeComponentsBounds();
            // final setup of TextObject & TextureObject lists
            InitializeGraphicComponents();
            // setup default Actions for a TextfieldObject
            InitializeActions();

            _initialized = false;
        }
        #endregion


        #region Protected Method - InitializeComponentsBounds()
        protected void InitializeComponentsBounds()
        {
            switch (_styleType)
            {
                case GuiResourceManager.ResourceManagerType.StyleDefault:
                    _scrollbar.RelativePosition = new Vector2((_bounds.X - 16.0f) / 2, 0.0f);
                    _scrollbar.Bounds = new Vector2(17.0f, this.Height);
                    break;

                case GuiResourceManager.ResourceManagerType.StyleHorizons:
                    _scrollbar.RelativePosition = new Vector2((_bounds.X - 16.0f) / 2, 0.0f);
                    _scrollbar.Bounds = new Vector2(17.0f, this.Height);
                    break;

                case GuiResourceManager.ResourceManagerType.StyleMac:
                    float crnHeight = _rcm.Load<Texture2D>("tf_crn_tr").Height;
                    _scrollbar.RelativePosition = new Vector2((_bounds.X - 15.0f) / 2, crnHeight / 2);
                    _scrollbar.Bounds = new Vector2(15.0f, this.Height - (crnHeight * 2));
                    break;

                default:
                    _scrollbar.RelativePosition = new Vector2((_bounds.X - 16.0f) / 2, 0.0f);
                    _scrollbar.Bounds = new Vector2(17.0f, this.Height);
                    break;
            }

            Background.RelativePosition = new Vector2(1, 1);
            Background.Bounds = new Vector2(_bounds.X - 2, _bounds.Y - 2);

            BorderLeft.RelativePosition = Statics.ZeroVector2;
            BorderLeft.Bounds = new Vector2(BorderLeft.Texture.Width, _bounds.Y);

            BorderRight.RelativePosition = new Vector2(_bounds.X, _bounds.Y);
            BorderRight.Bounds = new Vector2(BorderRight.Texture.Width, _bounds.Y);

            BorderTop.RelativePosition = Statics.ZeroVector2;
            BorderTop.Bounds = new Vector2(_bounds.X, BorderTop.Texture.Height);

            BorderBottom.RelativePosition = new Vector2(_bounds.X - _scrollbar.Width, _bounds.Y);
            BorderBottom.Bounds = new Vector2(_bounds.X, BorderBottom.Texture.Height);
            // set the Text(TextObject)'s RelativePosition to 3 / 2
            Text.RelativePosition = new Vector2(3, 2);
            // set the Cursor(TextureObject)'s RelativePosition to 3 / 2
            Cursor.RelativePosition = new Vector2(3, 2);
            Cursor.Bounds = new Vector2(Cursor.Texture.Width, _font.MeasureString("A").Y - 2);
            // refactor the Background, BorderTop, BorderRight, BorderBottom TextureObjects
            #region Refactor - Background, BorderTop, BorderRight, BorderBottom
            // correction on the BorderRight, BorderTop, BorderBottom and Background Textureobjects
            Background.Width = Background.Width - _scrollbar.Width;
            BorderRight.RelativePosition = new Vector2(BorderRight.X - _scrollbar.Width, BorderRight.Y);
            BorderBottom.Width = BorderBottom.Width - _scrollbar.Width;
            BorderTop.Width = BorderTop.Width - _scrollbar.Width;
            #endregion
        }
        #endregion

        #region Protected Method - InitializeGraphicComponents()
        protected void InitializeGraphicComponents()
        {
            Add(Background);
            Add(BorderLeft);
            Add(BorderRight);
            Add(BorderTop);
            Add(BorderBottom);
            if (_scrollbarVisible)
                Add(_scrollbar);
            else
            {
                // reset BorderRight TextureObject
                BorderRight.RelativePosition += new Vector2(_scrollbar.Width, 0);
                // reset BorderTop TextureObject
                BorderTop.Bounds += new Vector2(_scrollbar.Width, 0);
                // reset BorderBottom TextureObject
                BorderBottom.RelativePosition += new Vector2(_scrollbar.Width, 0);
                BorderBottom.Bounds += new Vector2(_scrollbar.Width, 0);
                // reset Background TextureObject
                Background.Bounds += new Vector2(_scrollbar.Width, 0);
            }
            Add(Cursor);
            Add(Text);
        }
        #endregion

        #region Protected Method - InitializeActions()
        protected void InitializeActions()
        {
            this.InstallAction(ActionFactory.MouseAction(this,
                              this.Background,
                              this.Text,
                              Action.Invoker.Texture,
                              Action.CommandType.Custom,
                              MouseAction.Inputs.MouseButtonPressed,
                              MouseAction.MouseButtons.Left,
                              "focus",
                              Action.KeyModifiers.None));

            this.InstallAction(ActionFactory.MouseAction(this,
                              this.Background,
                              this.Text,
                              Action.Invoker.Texture,
                              Action.CommandType.Custom,
                              MouseAction.Inputs.MouseButtonPressed,
                              MouseAction.MouseButtons.Left,
                              "unfocus",
                              Action.KeyModifiers.None));

            this.InstallAction(ActionFactory.KeyAction(this,
                              this.Background,
                              this.Text,
                              Action.Invoker.Texture,
                              Action.CommandType.Custom,
                              KeyAction.Inputs.KeyPressed,
                              new Keys[] { Keys.Enter },
                              "send",
                              Action.KeyModifiers.Alt));

        }
        #endregion

        #region Protected Method - ClipboardGet()
        protected string ClipboardGet()
        {
            string ret = "";
            if (System.Windows.Forms.Clipboard.ContainsText())
            {
                ret = System.Windows.Forms.Clipboard.GetText(System.Windows.Forms.TextDataFormat.UnicodeText);
                return ret;
            }
            else return ret;
        }
        #endregion

        #region Protected Method - ClipboardSet(string value)
        protected void ClipboardSet(string value)
        {
            System.Windows.Forms.Clipboard.SetText(value, System.Windows.Forms.TextDataFormat.UnicodeText);
        }
        #endregion

        
        #region Override Method - Rescale(Vector2 bounds)
        public override void Rescale(Vector2 bounds)
        {
            // (re)set bounds
            _bounds = bounds;
            // (re)set _keyProcessor
            _keyProcessor.LineWidth = (int)this.Bounds.X - 4;
            _lines = (int)((this.Bounds.Y + 2) / (_font.MeasureString("A").Y - 2));
            _keyProcessor.TotalLines = _lines;
            // Rescale / Reposition Background
            this.TextureObject(this._textureObjs.IndexOf(this.Background)).Bounds = new Vector2(_bounds.X - (BorderLeft.Width + BorderRight.Width), _bounds.Y -(BorderTop.Height + BorderBottom.Height));
            this.TextureObject(this._textureObjs.IndexOf(this.Background)).RelativePosition = new Vector2(BorderLeft.Width, BorderTop.Height);
            this.TextureObject(this._textureObjs.IndexOf(this.Background)).Width -= _scrollbar.Width + 1;
            // Rescale / Reposition BorderTop
            this.TextureObject(this._textureObjs.IndexOf(this.BorderTop)).Bounds = new Vector2(_bounds.X -(BorderLeft.Width + BorderRight.Width), BorderTop.Height);
            this.TextureObject(this._textureObjs.IndexOf(this.BorderTop)).RelativePosition = new Vector2(BorderLeft.Width, 0);
            this.TextureObject(this._textureObjs.IndexOf(this.BorderTop)).Width -= _scrollbar.Width + 1;
            // Rescale / Reposition BorderBottom
            this.TextureObject(this._textureObjs.IndexOf(this.BorderBottom)).Bounds = new Vector2(_bounds.X - (BorderLeft.Width + BorderRight.Width), BorderBottom.Height);
            this.TextureObject(this._textureObjs.IndexOf(this.BorderBottom)).RelativePosition = new Vector2(_bounds.X - (BorderLeft.Width), _bounds.Y);
            this.TextureObject(this._textureObjs.IndexOf(this.BorderBottom)).Width -= _scrollbar.Width;
            this.TextureObject(this._textureObjs.IndexOf(this.BorderBottom)).X -= _scrollbar.Width + 1;
            // Rescale / Reposition BorderLeft
            this.TextureObject(this._textureObjs.IndexOf(this.BorderLeft)).Bounds = new Vector2(BorderLeft.Width, _bounds.Y);
            this.TextureObject(this._textureObjs.IndexOf(this.BorderLeft)).RelativePosition = new Vector2(0, 0);
            // Rescale / Reposition BorderRight
            this.TextureObject(this._textureObjs.IndexOf(this.BorderRight)).Bounds = new Vector2(BorderRight.Width, _bounds.Y);
            this.TextureObject(this._textureObjs.IndexOf(this.BorderRight)).RelativePosition = new Vector2(_bounds.X, _bounds.Y);
            this.TextureObject(this._textureObjs.IndexOf(this.BorderRight)).X -= _scrollbar.Width + 1;
            // Rescale / Reposition Scrollbar
            this._scrollbar.RelativePosition = new Vector2(((_bounds.X - _scrollbar.Width )/ 2), 0);
            this._scrollbar.Rescale(new Vector2(this._scrollbar.Width, this._bounds.Y));
            // this.Scrollbar.Visible = false;
        }
        #endregion


        #region Override Method - Draw(GameTime gameTime, SpriteBatch sprite)
        public override void Draw(GameTime gameTime, SpriteBatch sprite)
        {
            if (this.IsInitialized)
            {
                foreach (InterfaceObject obj in _ios)
                {
                    obj.InstallInterface();
                }

                foreach (TextureObject obj in this._textureObjs)
                {
                    if (!obj.Equals(Cursor)) obj.Draw(sprite);
                    else
                    {
                        if (((gameTime.TotalRealTime.Milliseconds / 250) > 0) && _focused)
                        {
                            obj.Draw(sprite);
                        }
                    }
                }

                foreach (TextObject obj in _textObjs)
                {
                    obj.Draw(sprite);
                }
            }
        }
        #endregion

        #region Override Method - Update(GameTime gameTime)
        public override void Update(GameTime gameTime)
        {
            // check if the Textfield is focused (function added by default as Mouse.Click Action
            if (_focused && this.Visible && this.IsInitialized)
            {
                // invokes the KeyProcessor to check for input and get the line to the textfield
                #region Step 1 - Retrieve the current text from the KeyProcessor
                // save textmark of the last update iteration to _oldTextmark
                _oldTextmark = _textmark;
                // initialize and fill a temporary "content" string
                string _tempContent = _content;
                // Push the KeyProcessor to check the input for this Update iteration
                _keyProcessor.CheckInput(Keyboards.KeyboardLayout.EU_GE, _scrollbar);
                // get the KeyProcessor's current line to the "content" of the textfield
                _content = _keyProcessor.Log[_keyProcessor.LogLine];
                // get the KeyProcessor's current textmark position to the "textmark" of the textfield
                _textmark = _keyProcessor.Textmark;
                // set the number of lines which are above the current logline
                _linesUp = _lines - (_keyProcessor.Log.Count - _keyProcessor.LogLine);
                #endregion
                // filling the textfield with lines from the keyProcessor
                #region Step 2 - Writing down the lines to the textfield's text area
                // initialize the number of lines from the top (will be increased in the next loop)
                int lineFromTop = 0;
                // ===================================================================
                // Loop : iterate the lines above the active line (the textmark is in)
                // ===================================================================
                for (int i = 1; i <= _linesUp; i++)
                {
                    // check if the logLine is greater or equals to the lines above
                    // to provide a nother line to get from the KeyProcessors Log (Exception Avoidance)
                    if (_keyProcessor.LogLine >= i)
                    {
                        // paste the resulting line from the KeyProcessors log at the beginning of current Content
                        _content = _keyProcessor.Log[_keyProcessor.LogLine - i] + "\n" + _content;
                        // increase the lineFromTop counter (used later on to retrieve the still-to-add lines)
                        lineFromTop++;
                    }
                }
                // ===================================================================

                // initialize and set the lines still be able to add below the current content
                int linesBelow = ((_lines - 1) - lineFromTop);
                // ===================================================================
                // Loop : iterate the lines below the active line (the textmark is in)
                // ===================================================================
                for (int i = 1; i <= linesBelow; i++)
                {
                    // check if the amount of lines in the KeyProcessor's Log is greater then current logline + the (i)th line added below
                    if (_keyProcessor.Log.Count > (_keyProcessor.LogLine + i))
                    {
                        // recieve and append the (i)th line below current content
                        _content = _content + "\n" + _keyProcessor.Log[_keyProcessor.LogLine + i];
                    }
                }
                // ===================================================================

                // count of '\n' inside the current content (indicates how many rows are still blank in the textfield)
                int nextLines = Statics.Count('\n', _content);
                // initialize bool flag if the last line added and the current line in KeyProcessor's Log are equals
                bool linesMatch = false;
                // initialize and set liNL (lastIndexNextLine) to the index at the beginning of the last added content line
                int lINL = _content.LastIndexOf('\n') + 1;
                // check if lINL is greater or equals ro zero (Exception Avoidance, LastIndexOf-method may return '-1')
                // and if the last line added and the current line in KexProcessor's Log are equals (checked by the hashcode)
                if (lINL >= 0 && _content.Substring(lINL).GetHashCode().Equals(_keyProcessor.Log[_keyProcessor.LogLine].GetHashCode()))
                    // set the bool flag to true (otherwise it remains false)
                    linesMatch = true;

                // check if the bool-flag is true 
                // and if the KeyProcessor's Log can provide at least one more line of content
                if (linesMatch && _keyProcessor.Log.Count - 1 > _keyProcessor.LogLine)
                {
                    // initialize and set runsLeft to give a counter to the loop 
                    // value is 'the number of total lines' - 'number of current lines in content' 
                    int runsLeft = _lines - (nextLines + 1);
                    // ===================================================================
                    // Loop : iterate the runs left over to add to content
                    // ===================================================================
                    for (int i = 1; i <= runsLeft; i++)
                    {
                        // check if the KeyProcessor's Log provides a line (i) below the current line
                        if (_keyProcessor.Log.Count > (_keyProcessor.LogLine + i))
                        {
                            // recieve and append the (i)th line below current content
                            _content = _content + "\n" + _keyProcessor.Log[_keyProcessor.LogLine + i];
                        }
                    }
                    // ===================================================================
                }
                // check if the bool-flah is false (lines do not match)
                // and if the KeyProcessor's Log can provide at least one more line of content
                else if (!linesMatch && _keyProcessor.Log.Count - 1 > _keyProcessor.LogLine)
                {
                    // count of '\n' inside the current content (indicates how many rows are still blank in the textfield)
                    nextLines = Statics.Count('\n', _content);

                    // initialize and set runsLeft to give a counter to the loop 
                    // value is 'the number of total lines' - 'number of current lines in content' 
                    int runsLeft = (_lines - (nextLines + 1));
                    // ===================================================================
                    // Loop : iterate the runs left over to add to content
                    // ===================================================================
                    for (int i = 0; i < runsLeft; i++)
                    {
                        // calculate the index which the next line (to add) has in the KeyProcessor's Log
                        int index = _keyProcessor.LogLine + (nextLines - lineFromTop) + 1 + i;
                        // check it the KeyProcessor's Log contains at least a line on index
                        if (_keyProcessor.Log.Count > index)
                            // recieve and append the next line below current content
                            _content += "\n" + _keyProcessor.Log[index];
                    }
                }
                #endregion
                // check the text to be inside the textfield's bounds
                #region Step 3 - Check for the bounds
                // ===================================================================
                // Section to calculate the Cursors proper position on the Screen
                // ===================================================================
                // initialize and set the total width of the content, calculated by the MeasureString-method + 3
                int contentTotalWidth = (int)_font.MeasureString(_content).X + 3;
                // initialize and set the total height of the content, calculated by the MeasureString-method
                int contentTotalHeight = (int)_font.MeasureString(_content).Y;

                // check if the allowOutOfBoundsContent-flag is true
                // and if the content total width is greater than the textfield's bounds - 20
                if (!_allowOutOfBoundsContent &&
                    ((_scrollbarVisible && (contentTotalWidth > (_bounds.X - _scrollbar.Width - 3)))
                    || (!_scrollbarVisible && (contentTotalWidth > (_bounds.X - 3)))))
                {
                    // reset the current content to the previously saved "old" content (from last update iteration)
                    _content = _tempContent;
                    // reset the KeyProcessor's Textmark to the previously saved "old" textmark (from last update iteration)
                    _keyProcessor.Textmark = _oldTextmark;
                    // trim the KeyProcessor's Content and current Log Line to the length of textmark index
                    _keyProcessor.TrimBehindTextmark();
                    // reset the textfield's textmark to the "old" textmark
                    _textmark = _oldTextmark;
                }
                // achieve the value of the current content (from this update iteration) to the temporary content
                else _tempContent = _content;
                // fill the TextObjects Text-property with the temporary content
                Text.Text = _tempContent;
                #endregion
                // calculate the proper position for the cursor on the textfield
                #region Step 4 - Calculate cursor x and y position
                // initialize and set Cursor xPos to a default value of 3
                int xPos = 3;
                // check if the current KeyProcessor's content line uneqauls null/""
                if (_keyProcessor.Content != "")
                    // set Cursor xPos to the width of the MeasureString-method result of the substring 
                    // of KeyProcessor's content line from index 0 to textmark position
                    xPos = (int)_font.MeasureString(_keyProcessor.Content.Substring(0, _keyProcessor.Textmark)).X + 2;

                // initialize and set Cursor yPos to a default value of 2
                int yPos = 4;
                // check if the KeyProcessor's Log contains at least ohne line
                if (_keyProcessor.Log.Count >= 1)
                {
                    // set Cursor yPos to the number of lines from the top 
                    // multiplied with the heigth of the MeasureString-method for a default string substracted by 2
                    yPos = (lineFromTop) * (int)(_font.MeasureString("A").Y - 2);
                }

                // set the Cursor(TextureObject)'s Relative Position to both of xPos and yPos
                Cursor.RelativePosition = new Vector2(xPos, yPos);
                #endregion
            }
            // call base update method
            base.Update(gameTime);
        }
        #endregion

        #region Override Method - ExecuteCommand(string command)
        public override void ExecuteCommand(string command)
        {
            // execute TextfieldObject custom command 'focus'
            if (command.Equals("focus") && Visible)
            {
                _focused = true;
                InterfaceManager.GetInstance(Game).DisableAll();
                InterfaceManager.GetInstance(Game).Enable(this.Actions[1]);
                InterfaceManager.GetInstance(Game).Enable(this.Actions[2]);
                InterfaceManager.GetInstance(Game).Enable(this._scrollbar.Actions[0]);
                InterfaceManager.GetInstance(Game).Enable(this._scrollbar.Actions[1]);
            }
            // execute TextfieldObject custom command 'unfocus'
            else if (command.Equals("unfocus") && Visible)
            {
                _focused = false;
                InterfaceManager.GetInstance(Game).EnableAll();
                InterfaceManager.GetInstance(Game).Disable(this.Actions[1]);
                InterfaceManager.GetInstance(Game).Disable(this.Actions[2]);
            }
            // execute TextfieldObject custom command 'send'
            else if (command.Equals("send"))
            {
                // check if component is focused
                if (_focused)
                {
                    // check if target is not null to do send the text to
                    if (_textTarget != null)
                    {
                        // set tthe Text to the targetObject
                        string tempContent = "";
                        foreach(string line in _keyProcessor.Log)
                        {
                            tempContent += line + "\n";
                        }
                        // trim last \n (line-break) from the content string
                        tempContent = tempContent.Remove(tempContent.Length - 1);
                        _textTarget.Text = tempContent;
                        // final handling for text and textmarkposition (clear and set to 0)
                        // _content = "";
                        _textmark = 0;
                    }
                }
            }
        }
        #endregion
    
        #region Override Method - DoScroll(IScrollClass.ScrollDirection direction)
        public override void DoScroll(IScrollClass.ScrollDirection direction)
        {
            if (direction == IScrollClass.ScrollDirection.Up)
            {
                _keyProcessor.Invoke(Keys.Up);
                Console.WriteLine("Do Scroll in direction" + direction.ToString());
            }
            else if (direction == IScrollClass.ScrollDirection.Down)
            {
                _keyProcessor.Invoke(Keys.Down);
                Console.WriteLine("Do Scroll in direction" + direction.ToString());
            }
        }
        #endregion
    }
}